package me.zhengjie.modules.quartz.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.quartz.service.RestService;
import me.zhengjie.modules.quartz.service.dto.RestTaskConfig;
import me.zhengjie.modules.quartz.service.dto.RestTaskRequestConfig;
import me.zhengjie.modules.quartz.service.dto.RestTaskResponseConfig;
import me.zhengjie.utils.RedisUtils;
import me.zhengjie.utils.SpringContextHolder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDate;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Component
public class RestServiceImpl implements RestService {

    private RestTemplate restTemplate;

    public RestServiceImpl(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    ThreadLocal<HttpHeaders> threadLocal = new ThreadLocal<>();

    Pattern arrayIndexPattern = Pattern.compile("^(\\[)(\\d*)(\\])$");

    @Override
    public String doRun(RestTaskConfig config) {

        buildRequestHeaders(config.getRequest());

        String result = request(config.getRequest());

        Object jsonObject = handleResult(config.getResponse(), result);

        resolveResult(config.getResponse(), jsonObject);

        return config.getResponse().getCallBackMsg();
    }

    public Object resolveResult(RestTaskResponseConfig response, Object json) {

        String resourcePath = response.getResolvePath();
        Object v = json;
        if (StringUtils.isNotBlank(resourcePath)) {
            // a-> b -> [1] || [0]->a
            String[] paths = resourcePath.split("->");
            for (String path: paths) {
                Matcher matcher = arrayIndexPattern.matcher(path);
                if (matcher.matches()) {
                    String index = matcher.group(2);
                    if (StringUtils.isNotBlank(index)) {
                        v = ((JSONArray) v).get(Integer.parseInt(index));
                    }
                } else {
                    if (v instanceof JSONObject) {
                        v = ((JSONObject) v).get(path);
                    } else if (v instanceof JSONArray) {
                        JSONArray value = (JSONArray) v;
                        List<String> result = new ArrayList<>(value.size());
                        for (int offset = 0; offset < value.size(); offset++) {
                            final String checkValue = value.getJSONObject(offset).getString(path);
                            if (response.getIgnoreValues().stream().noneMatch(checkValue::endsWith)) {
                                result.add(response.getBaseUrl() + checkValue);
                            }
                        }
                        v = result;
                    }
                }
            }
        }
        final Object checkValue = v;
        if (v instanceof String &&
                response.getIgnoreValues().stream().noneMatch(((String) checkValue)::endsWith)) {
            v = response.getBaseUrl() + checkValue;
        }

        if (StringUtils.isNotBlank(response.getStoreTo())) {
            if ("redis".equalsIgnoreCase(response.getStoreTo())) {
                if (v instanceof String) {
                    SpringContextHolder.getBean(RedisUtils.class).set(String.format(response.getStoreTarget(), LocalDate.now().toString()), v);
                } else if (v instanceof List) {
                    SpringContextHolder.getBean(RedisUtils.class).lSet(String.format(response.getStoreTarget(), LocalDate.now().toString()), (List) v);
                } else {
                    throw new RuntimeException(String.format("存储失败，不支持的类型【%s】", v));
                }
            } else {
                throw new RuntimeException(String.format("不支持的存储类型类型【%s】", response.getStoreTo()));
            }
        }
        return v;

    }

    private HttpHeaders buildRequestHeaders(RestTaskRequestConfig request) {
        HttpHeaders headers = new HttpHeaders();
        threadLocal.set(headers);
        Optional.ofNullable(request.getCookies()).ifPresent(c -> {
            List<String> cookies = new ArrayList<>(c);
            headers.put(HttpHeaders.COOKIE, cookies);
        });
        Optional.ofNullable(request.getTokenKey()).ifPresent(key -> headers.put(key, Collections.singletonList(request.getTokenValue())));

        Optional.ofNullable(request.getContentType()).ifPresent(ct -> headers.setContentType(MediaType.parseMediaType(ct)));

        Optional.ofNullable(request.getAccept()).ifPresent(accept -> headers.add("Accept", accept));
        // 添加默认的User-Agent
        headers.add("User-Agent", "PostmanRuntime/7.26.2");
        return headers;
    }

    private Object handleResult(RestTaskResponseConfig response, String result) {
        if ("JSON".equalsIgnoreCase(response.getResultType())) {
            if ("JSONObject".equalsIgnoreCase(response.getClassName())) {
                return JSONObject.parseObject(result);
            } else if ("JSONArray".equalsIgnoreCase(response.getClassName())) {
                return JSONArray.parseArray(result);
            } else {
                return JSON.parse(result);
            }
        } else {
            throw new RuntimeException(String.format("不支持的返回值类型%s", response.getResultType()));
        }
    }


    private String request(RestTaskRequestConfig request) {
        String url = request.getUrl();
        HttpEntity httpEntity = new HttpEntity(request.getParams(), threadLocal.get());
        threadLocal.remove();
        ResponseEntity<String> result;
        if (HttpMethod.POST.equals(request.getMethod())) {
            result = restTemplate.postForEntity(url, httpEntity, String.class);
        } else if (HttpMethod.GET.equals(request.getMethod())) {
            result = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
        } else {
            throw new BadRequestException(HttpStatus.METHOD_NOT_ALLOWED, "仅支持Get/Post方式");
        }

        if (result.getStatusCode() == HttpStatus.MOVED_PERMANENTLY || result.getStatusCode() == HttpStatus.OK) {
            return result.getBody();
        }
        throw new BadRequestException(result.getStatusCode(), result.getBody());
    }
}
